using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Text.RegularExpressions;
using System.IO;
using System.Web;

namespace FeedValidation
{
    public class Validate
    {

        private const string SOAP_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope";
        private const string TARGET_URL = "http://validator.w3.org/feed/check.cgi";

        public ValidationResults ValidateFeed(System.Xml.XmlDocument feed)//List<Message> ValidateFeed(System.Xml.XmlDocument feed)
        {

            if (feed == null)
            {
                return null;
            }
            else
            {
                string rssText = feed["rss"].OuterXml;
                return ValidateFeed(rssText);
            }
        }

        public ValidationResults ValidateFeed(String rssText)//List<Message> ValidateFeed(System.Xml.XmlDocument feed)
        {

            if (String.IsNullOrEmpty(rssText))
            {
                return null;
            }
            else
            {

                #region "original calls against feedvalidator.org"

                try
                {
                    System.Net.HttpWebRequest hwr = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("http://validator.w3.org/feed/check.cgi?output=soap12");//"http://www.feedvalidator.org/");

                    System.IO.MemoryStream ms = new System.IO.MemoryStream();


                    List<int> startPositions = new List<int>();
                    int startPos = 0;

                    do
                    {
                        int itemIndex = rssText.ToLower().IndexOf("<item>", startPos);
                        if (itemIndex > -1)
                        {
                            startPositions.Add(itemIndex);
                            startPos = itemIndex + "<item>".Length;
                        }
                    } while (rssText.ToLower().IndexOf("<item>",startPos) > -1);

                    startPositions.Add(rssText.Length);

                    string messageToSend = String.Format("rawdata={0}&manual=1&output=soap12", HttpUtility.UrlEncode(rssText));
                    Byte[] buffer;

                    buffer = System.Text.Encoding.UTF8.GetBytes(messageToSend);
                    
                    int byteCount = buffer.Length; //System.Text.Encoding.UTF8.GetByteCount(message.ToString());
                    //hwr.Proxy = new System.Net.WebProxy("http://localhost:8888",false);
                    
                    hwr.ContentType = "application/x-www-form-urlencoded";

                    hwr.ContentLength = byteCount;
                    hwr.Method = System.Net.WebRequestMethods.Http.Post;

                    StreamWriter sw = new StreamWriter(hwr.GetRequestStream());
                    sw.AutoFlush = true;
                    sw.Write(messageToSend);
                    sw.Close();
                    
                    System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)hwr.GetResponse();

                    if (resp.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        resp.Close();
                        return null;
                    }
                    else
                    {
                        System.Xml.XmlDocument xdoc = new XmlDocument();
                        xdoc.Load(resp.GetResponseStream());
                        resp.Close();
                        
                        XmlNode envelope = xdoc["env:Envelope"];//, SOAP_NAMESPACE];
                        XmlNode body = envelope["env:Body"];//, SOAP_NAMESPACE];
                        XmlNode response = body["m:feedvalidationresponse"];//, "http://feedvalidator.org/"];


                        XmlNode valid = response["m:validity"];

                        bool isValid = false;
                        bool.TryParse(valid.InnerText, out isValid);

                        XmlNode errors;
                        XmlNode warnings;
                        XmlNode informations;

                        errors = response["m:errors"];
                        warnings = response["m:warnings"];
                        informations = response["m:informations"];



                        XmlNodeList errorList = errors["m:errorlist"].ChildNodes;

                        XmlNodeList warningList = warnings["m:warninglist"].ChildNodes;

                        XmlNodeList informationList = informations["m:infolist"].ChildNodes;

                        ValidationResults results = new ValidationResults();

                        results.Errors= GetMessages(errorList);
                        results.Warnings = GetMessages(warningList);
                        results.Informations = GetMessages(informationList);
                        results.Valid = isValid;


                        return results;
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
                    return null;
                } 

                #endregion

                //return messages;
            }

        }

        private static List<Message> GetMessages(XmlNodeList messages)
        {
            int messageCount = messages.Count;
            List<Message> results = new List<Message>();

            foreach (XmlNode msgNode in messages)
            {
                Message msg = new Message();

                if (msgNode["column"] != null)
                {
                    msg.column = Int32.Parse(msgNode["column"].InnerText);
                    //int itemIndex = 0;
                    //while (itemIndex < startPositions.Count && startPositions[itemIndex] < msg.column)
                    //{
                    //    itemIndex++;
                    //}
                    //if (itemIndex < startPositions.Count)
                    //    msg.ItemPosition = itemIndex;
                    //else
                    //    msg.ItemPosition = -1;

                }

                if (msgNode["level"] != null)
                    msg.level = msgNode["level"].InnerText;

                if (msgNode["line"] != null)
                    msg.line = Int32.Parse(msgNode["line"].InnerText);

                if (msgNode["text"] != null)
                    msg.text = msgNode["text"].InnerText;

                if (msgNode["type"] != null)
                    msg.type = msgNode["type"].InnerText;

                results.Add(msg);
            }

            return results;
        }

    }


    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://feedvalidator.org/")]
    public class Message
    {
        private int itemPosition;

        public int ItemPosition
        {
            get { return itemPosition; }
            set { itemPosition = value; }
        }
	

        private string levelField;

        private string typeField;

        private int lineField;

        private int columnField;

        private string msgcountField;

        private string textField;

        private System.Xml.XmlElement[] anyField;

        /// <remarks/>
        public string level
        {
            get
            {
                return this.levelField;
            }
            set
            {
                this.levelField = value;
            }
        }

        /// <remarks/>
        public string type
        {
            get
            {
                return this.typeField;
            }
            set
            {
                this.typeField = value;
            }
        }

        /// <remarks/>
        public int line
        {
            get
            {
                return this.lineField;
            }
            set
            {
                this.lineField = value;
            }
        }

        /// <remarks/>
        public int column
        {
            get
            {
                return this.columnField;
            }
            set
            {
                this.columnField = value;
            }
        }

        /// <remarks/>
        public string msgcount
        {
            get
            {
                return this.msgcountField;
            }
            set
            {
                this.msgcountField = value;
            }
        }

        /// <remarks/>
        public string text
        {
            get
            {
                return this.textField;
            }
            set
            {
                this.textField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlAnyElementAttribute()]
        public System.Xml.XmlElement[] Any
        {
            get
            {
                return this.anyField;
            }
            set
            {
                this.anyField = value;
            }
        }
    }


}



